package impl.myjdkimpl;

import utils.compiler.StringifyJavaClassCompiler;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;


public class MyProxy {

    private  static  final  String PROXY_CLASS_NAME = "$MyProxy0";
    private  static  final  String PROXY_CLASS_FILE_NAME = PROXY_CLASS_NAME+".java";

    public  static  Object newProxyInstance(MyClassLoader loader,
                                            Class<?> interfaces,
                                            MyInvocationHandler invocationHandler) throws Exception {

        Method[] methods = interfaces.getDeclaredMethods();
        StringBuffer stringifyJavaClass = new StringBuffer();

        stringifyJavaClass
                .append("import java.lang.reflect.Method; " )
                .append(" import ").append(MyInvocationHandler.class.getName()).append("; ")
                .append("public class ").append(PROXY_CLASS_NAME).append(" implements ")
                .append(interfaces.getName()).append(" { ")
                .append(" MyInvocationHandler h;")
                .append(" public ").append(PROXY_CLASS_NAME).append(" (MyInvocationHandler h){")
                .append(" this.h = h;}")
                .append(getStringifyMethods(methods,interfaces)).append("}");

        String currentDir = MyClassLoader.class.getProtectionDomain().getCodeSource().getLocation().getPath();
        File file = new File(currentDir + File.separator + PROXY_CLASS_FILE_NAME);

        StringifyJavaClassCompiler.compile(stringifyJavaClass.toString(),file);

        Class $MyProxy4 = loader.findClass(PROXY_CLASS_NAME);
        Constructor constructor = $MyProxy4.getConstructor(MyInvocationHandler.class);
        Object o = constructor.newInstance(invocationHandler);

        return  o;
    }

    private static String getStringifyMethods(Method[] methods,Class<?> inf) {
        StringBuffer stringifyMethod = new StringBuffer();
        for(Method method : methods) {
            stringifyMethod.append("public void ").append(method.getName())
                    .append("()").append(" { try{")
                    .append(" Method method1 = ").append(inf.getName())
                    .append(".class.getMethod(\"").append(method.getName())
                    .append("\", new Class[]{});")
                    .append("this.h.invoke(this,method1,null);")
                    .append("}catch(Throwable ex){} }");
        }
        return stringifyMethod.toString();
    }
}








